import { ValidationError } from 'sequelize';

// 自定义错误类
export class AppError extends Error {
  constructor(message, statusCode = 500, code = null) {
    super(message);
    this.statusCode = statusCode;
    this.code = code;
    this.isOperational = true;
    
    Error.captureStackTrace(this, this.constructor);
  }
}

// 业务错误类
export class BusinessError extends AppError {
  constructor(message, code = null) {
    super(message, 400, code);
  }
}

// 认证错误类
export class AuthError extends AppError {
  constructor(message = '认证失败') {
    super(message, 401, 'AUTH_ERROR');
  }
}

// 权限错误类
export class PermissionError extends AppError {
  constructor(message = '权限不足') {
    super(message, 403, 'PERMISSION_ERROR');
  }
}

// 资源不存在错误类
export class NotFoundError extends AppError {
  constructor(message = '资源不存在') {
    super(message, 404, 'NOT_FOUND');
  }
}

// 验证错误类
export class ValidateError extends AppError {
  constructor(message, errors = null) {
    super(message, 422, 'VALIDATE_ERROR');
    this.errors = errors;
  }
}

// 处理Sequelize验证错误
const handleSequelizeValidationError = (error) => {
  const errors = error.errors.map(err => ({
    field: err.path,
    message: err.message,
    value: err.value
  }));
  
  return new ValidateError('数据验证失败', errors);
};

// 处理Sequelize唯一约束错误
const handleSequelizeUniqueConstraintError = (error) => {
  const field = error.errors[0]?.path || 'unknown';
  const message = `${field} 已存在`;
  return new BusinessError(message, 'DUPLICATE_ERROR');
};

// 处理Sequelize外键约束错误
const handleSequelizeForeignKeyConstraintError = (error) => {
  return new BusinessError('关联数据不存在或已被删除', 'FOREIGN_KEY_ERROR');
};

// 处理JWT错误
const handleJWTError = (error) => {
  if (error.name === 'JsonWebTokenError') {
    return new AuthError('无效的访问令牌');
  }
  if (error.name === 'TokenExpiredError') {
    return new AuthError('访问令牌已过期');
  }
  return new AuthError('令牌验证失败');
};

// 开发环境错误响应
const sendErrorDev = (err, res) => {
  res.status(err.statusCode).json({
    code: err.statusCode,
    message: err.message,
    data: {
      error: err,
      stack: err.stack,
      errors: err.errors
    }
  });
};

// 生产环境错误响应
const sendErrorProd = (err, res) => {
  // 操作性错误：发送给客户端
  if (err.isOperational) {
    const response = {
      code: err.statusCode,
      message: err.message,
      data: err.errors ? { errors: err.errors } : null
    };

    res.status(err.statusCode).json(response);
  } else {
    // 编程错误：不泄露错误详情
    console.error('ERROR 💥', err);

    res.status(500).json({
      code: 500,
      message: '服务器内部错误',
      data: null
    });
  }
};

// 主错误处理中间件
export const errorHandler = (err, req, res, next) => {
  let error = { ...err };
  error.message = err.message;
  error.statusCode = err.statusCode || 500;

  // 记录错误日志
  if (error.statusCode >= 500) {
    console.error('Server Error:', {
      message: error.message,
      stack: error.stack,
      url: req.url,
      method: req.method,
      ip: req.ip,
      userAgent: req.get('User-Agent')
    });
  }

  // 处理不同类型的错误
  if (error.name === 'SequelizeValidationError') {
    error = handleSequelizeValidationError(error);
  } else if (error.name === 'SequelizeUniqueConstraintError') {
    error = handleSequelizeUniqueConstraintError(error);
  } else if (error.name === 'SequelizeForeignKeyConstraintError') {
    error = handleSequelizeForeignKeyConstraintError(error);
  } else if (error.name === 'JsonWebTokenError' || error.name === 'TokenExpiredError') {
    error = handleJWTError(error);
  } else if (error.code === 'ENOENT') {
    error = new NotFoundError('文件不存在');
  } else if (error.code === 'LIMIT_FILE_SIZE') {
    error = new BusinessError('文件大小超出限制');
  } else if (error.code === 'LIMIT_UNEXPECTED_FILE') {
    error = new BusinessError('不支持的文件类型');
  }

  // 确保错误有状态码
  if (!error.statusCode) {
    error.statusCode = 500;
    error.isOperational = false;
  }

  // 根据环境发送错误响应
  if (process.env.NODE_ENV === 'development') {
    sendErrorDev(error, res);
  } else {
    sendErrorProd(error, res);
  }
};

// 异步错误捕获包装器
export const catchAsync = (fn) => {
  return (req, res, next) => {
    Promise.resolve(fn(req, res, next)).catch(next);
  };
};

// 404处理中间件
export const notFound = (req, res, next) => {
  const error = new NotFoundError(`路由 ${req.originalUrl} 不存在`);
  next(error);
};
